home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-26 | 45.4 KB | 1,301 lines |
- The Pascal Wizard's Library
- =-------------------------=
- Version 1.4
-
- PasWiz Copyright (c) 1990-1993 Thomas G. Hanlin III
-
-
-
- This is PasWiz, a library of assorted routines for use with
- Turbo Pascal, Quick Pascal, and compatible compilers. Full
- Pascal source code is now included with the shareware version.
- Assembly language sources are provided to registered owners. The
- PasWiz collection is copyrighted, but may be distributed as long
- as the following conditions are met:
-
- All PasWiz files must be distributed together as a unit in
- unmodified form. No files may be left out or added.
-
- YOU USE THIS LIBRARY AT YOUR OWN RISK. It has been tested by me
- on my own computer, but I will not assume any responsibility for
- any problems which PasWiz may cause you. If you run into a
- problem, please let me know about it, and I will do my best to
- verify and repair the error.
-
- Shareware operates on a "try before you buy" basis. It is
- expected that if you find PasWiz useful, you will register your
- copy. You may not use PasWiz routines in programs intended for
- distribution unless you have registered. Registration entitles
- you to receive the latest version of PasWiz, complete with full
- source code. See the ORDER.FRM file for details.
-
- So who's the Pascal Wizard? With PasWiz, you are! Read this tome
- well, for invoking these routines without proper preparation may
- bring unexpected results. Cape and hat (optional) not included.
-
- Table of Contents page 2
-
-
-
- Overview and Legal Info .................................... 1
-
- BCD Math ................................................... 3
-
- Equipment Info ............................................. 7
-
- Expression Evaluator ...................................... 10
-
- Extensions to Pascal's Math ............................... 11
-
- Joystick Support .......................................... 13
-
- Keyboard Control .......................................... 14
-
- String Stuff .............................................. 18
-
- Music ..................................................... 22
-
- Mouse ..................................................... 23
-
- BCD Math page 3
-
- Unit: BCD
-
-
-
- Some of you may not have heard of BCD math, or at least not have
- more than a passing acquaintance with the subject. BCD (short
- for Binary-Coded Decimal) is a way of encoding numbers. It
- differs from the normal method of handling numbers in several
- respects. On the down side, BCD math is much slower than normal
- math and the numbers take up more memory. However, the benefits
- may far outweigh these disadvantages, depending on your
- application: BCD math is absolutely precise within your desired
- specifications, and you can make a BCD number as large as you
- need. If your applications don't require great range or
- precision out of numbers, normal Pascal math is probably the
- best choice. For scientific applications, accounting,
- engineering and other demanding tasks, though, BCD may be just
- the thing you need.
-
- The BCD math routines provided by PasWiz allow numbers of up to
- 255 digits long (the sign counts as a digit, but the decimal
- point doesn't). You may set the decimal point to any position
- you like, as long as there is at least one digit position to the
- left of the decimal.
-
- Since Pascal doesn't support BCD numbers directly, we store the
- BCD numbers in strings. The results are not in text format and
- won't mean much if displayed. A conversion routine allows you to
- change a BCD number to a text string in any of a variety of
- formats.
-
- Note that the BCD math handler doesn't yet track
- overflow/underflow error conditions. If you anticipate that this
- may be a problem, it would be a good idea to screen your input
- or to make the BCD range large enough to avoid these errors.
-
- Let's start off by considering the BCD range. This is kept in
- two integer variables, LDigits and RDigits, which can be
- accessed by your program. These variables specify the maximum
- number of digits to the left and to the right of the decimal
- point. There must be at least one digit on the left, and the
- total number of digits must be less than 255. The BCD strings
- will have a length that's one larger than the total number of
- digits, to account for the sign of the number. The decimal point
- is implicit and doesn't take up any extra space.
-
- It is assumed that you will only use one size of BCD number in
- your program-- there are no provisions for handling mixed-length
- BCD numbers. Of course, you could manage that yourself with a
- little extra work, if it seems like a useful capability. If you
- don't change LDigits or RDigits, the default size of the BCD
- numbers will be 32 (20 to the left, 11 to the right, 1 for the
- sign).
-
- BCD Math page 4
-
- Unit: BCD
-
-
-
- Before doing any BCD calculations, you must have some BCD
- numbers! The BCDSet routine takes a number in text string form
- and converts it to BCD:
-
- TextSt := '1234567890.50';
- Nr := BCDSet(TextSt);
- { FUNCTION BCDSet (TextSt: String): String; }
-
- If your numbers are stored as actual numbers, you can convert
- them to a text string with Pascal's Str procedure, then to BCD:
-
- Str(Number, TextSt);
- Nr := BCDSet(TextSt);
-
- BCD numbers can also be converted back to text strings, of
- course. You may specify how many digits to the right of the
- decimal to keep (the number will be truncated, not rounded). If
- the RightDigits value is positive, trailing zeros will be kept;
- if negative, trailing zeros will be removed. There are also
- various formatting options which may be used. Here's how it
- works:
-
- FUNCTION BCDFormat (Nr: String; HowToFormat,
- RightDigits: Integer): String;
-
- The HowToFormat value may be any combination of the following
- (just add the numbers of the desired formats together):
-
- 0 plain number
- 1 use commas to separate thousands, etc
- 2 start number with a dollar sign
- 4 put the sign on the right instead of the left side
- 8 use plus sign instead of space if nr is not negative
-
- The BCD math functions are pretty much self-explanatory, so I'll
- keep the descriptions brief. The single-parameter functions are
- listed on the next page.
-
- BCD Math page 5
-
- Unit: BCD
-
-
-
- { absolute value }
- FUNCTION BCDAbs (Nr: String): String;
-
- { cosine }
- FUNCTION BCDCos (Nr: String): String;
-
- { cotangent }
- FUNCTION BCDCot (Nr: String): String;
-
- { cosecant }
- FUNCTION BCDCsc (Nr: String): String;
-
- { convert degrees to radians }
- FUNCTION BCDDeg2Rad (Nr: String): String;
-
- { the constant "e" }
- FUNCTION BCDe: String;
-
- { factorial }
- FUNCTION BCDFact (Nr: Integer): String;
-
- { fractional part of number }
- FUNCTION BCDFrac (Nr: String): String;
-
- { integer part of number }
- FUNCTION BCDInt (Nr: String): String;
-
- { negation }
- FUNCTION BCDNeg (Nr: String): String;
-
- { the constant "pi" }
- FUNCTION BCDpi: String;
-
- { convert radians to degrees }
- FUNCTION BCDRad2Deg (Nr: String): String;
-
- { secant }
- FUNCTION BCDSec (Nr: String): String;
-
- { signum }
- FUNCTION BCDSgn (Nr: String): Integer;
-
- { sine }
- FUNCTION BCDSin (Nr: String): String;
-
- { square root }
- FUNCTION BCDSqrt (Nr: String): String;
-
- { tangent }
- FUNCTION BCDTan (Nr: String): String;
-
- BCD Math page 6
-
- Unit: BCD
-
-
-
- Notes on the single-parameter functions:
-
- The signum function returns an integer based on the sign of
- the BCD number:
-
- -1 if the BCD number is negative
- 0 if the BCD number is zero
- 1 if the BCD number is positive
-
- BCDpi is accurate to the maximum level afforded by the BCD
- functions. BCDe is accurate to as many as 115 decimal places.
- The actual accuracy, of course, depends on the size of BCD
- numbers you've chosen.
-
- The trigonometric functions (cos, sin, tan, sec, csc, cot)
- expect angles in radians. BCDDeg2Rad and BCDRad2Deg will allow
- you to convert back and forth between radians and degrees.
-
-
-
- Here is a list of the two-parameter functions:
-
-
- { addition }
- FUNCTION BCDAdd (Nr1, Nr2: String): String;
-
- { divide 1st by 2nd }
- FUNCTION BCDDiv (Nr1, Nr2: String): String;
-
- { multiplication }
- FUNCTION BCDMul (Nr1, Nr2: String): String;
-
- { subtract 2nd from 1st }
- FUNCTION BCDSub (Nr1, Nr2: String): String;
-
- { raise to a power }
- FUNCTION BCDPower (Nr: String; Power: Integer): String;
-
- { compare two numbers }
- FUNCTION BCDCompare (Nr1, Nr2: String): Integer;
-
- The comparison function returns an integer which reflects how
- the two numbers compare to each other:
-
- -1 Nr1 < Nr2
- 0 Nr1 = Nr2
- 1 Nr1 > Nr2
-
- Equipment Info page 7
-
- Unit: Equipment
-
-
-
- The equipment unit gives you information about the computing
- environment. This includes both installed software and hardware.
-
- The first function allows you to determine if an "enhanced"
- keyboard (101-key) is installed. It may not be able to figure
- out what the keyboard is on some older not-quite-clone PCs, in
- which case it will take the safe way out and report that there
- is no enhanced keyboard. This function returns -1 if there is an
- enhanced keyboard present, 0 if not.
-
- FUNCTION EnhKbd: Integer;
-
- Want to know the type of processor (CPU) being used? Can do!
-
- FUNCTION Processor: Integer;
-
- The results will be reported as a number which can be decoded as
- follows:
-
- 0 NEC V20
- 1 8088 or 8086
- 2 80186
- 3 80286
- 4 80386
- 5 80486
-
- Maybe you'd like to check for a CD-ROM drive:
-
- FUNCTION CDROM: Integer;
-
- This tells you how many logical drives exist, if there is a
- CD-ROM available. If not, it will return 0. Note that the CD-ROM
- installation check conflicts with the GRAPHICS.COM installation
- check for DOS 4.0, due to some screw-up at IBM or Microsoft. I'm
- not yet sure whether DOS 5.0 is similarly afflicted.
-
- The number of floppy drives installed is retrieved with this:
-
- FUNCTION Floppies: Integer;
-
- To get the number of serial (COM) ports and parallel (LPT)
- ports, use the following functions:
-
- FUNCTION CommPorts: Integer;
-
- FUNCTION PrtPorts: Integer;
-
- Equipment Info page 8
-
- Unit: Equipment
-
-
-
- Now, there may be up to four floppy drives in a system; however,
- the AT CMOS data area only directly supports two. This makes it
- easy to find out what kind of drives the first two are, but not
- the second two, if any. Such is life.
-
- PROCEDURE FloppyType (VAR Drive1, Drive2: Integer);
-
- The results from FloppyType are returned as follows:
-
- 0 no drive
- 1 5 1/4" 360K
- 2 5 1/4" 1.2M
- 3 3 1/2" 720K
- 4 3 1/2" 1.44M
- 5 3 1/2" 2.88M
-
- Result codes of 6-7 are also available, but are not yet defined.
-
- New memory types sure have burgeoned over the years... expanded,
- extended, and now XMS. There are routines to check all of these:
-
- { amount of extended memory installed }
- FUNCTION AllExtMem: LongInt;
-
- { BIOS extended memory available }
- FUNCTION GetExtM: LongInt
-
- { amount of expanded memory (a page is 16 Kbytes) }
- PROCEDURE GetEMSm (VAR TotalPages, FreePages: Integer);
-
- { amount of XMS memory (returned in kilobytes) }
- PROCEDURE GetXMSm (VAR LargestFreeBlock, TotalFree: LongInt);
-
- When you're dealing with extended memory, whether it be
- BIOS-type or using the XMS standard, the results are returned in
- kilobytes. Multiply 'em by 1024 to convert to bytes. When you're
- dealing with expanded memory (EMS), the results are in pages of
- 16,384 bytes.
-
- Equipment Info page 9
-
- Unit: Equipment
-
-
-
- A few more routines to get the versions of the EMS and XMS
- drivers, if any:
-
- PROCEDURE GetEMSv (VAR MajorV, MinorV: Integer);
-
- PROCEDURE GetXMSv (VAR MajorV, MinorV: Integer);
-
- These return the major and minor version numbers as two separate
- integers. For example, EMS 4.0 would return major version 4,
- minor version 0.
-
- It's nice to know a little about the operating environment. With
- the below routines, you can find out what the DOS version is;
- what version of 4DOS, if any, is in use; and whether Microsoft
- Windows is running.
-
- PROCEDURE GetDOSv (VAR MajorV, MinorV: Integer);
-
- PROCEDURE Get4DOSv (VAR MajorV, MinorV: Integer);
-
- PROCEDURE WinCheck (VAR MajorV, MinorV: Integer);
-
- These return results as major and minor version numbers, as
- discussed above. The Get4DOSv and WinCheck routines return
- zeroes if 4DOS and Windows, respectively, are not in use.
-
- There are a couple of curious features of GetDOSv to keep in
- mind. If the version is 10 or higher, you're running under OS/2.
- DOS version 10 is actually OS/2 1.0, version 20 is OS/2 2.0, and
- so on. Secondly, if you're using DOS 5.0, the version reported
- may not be 5.0-- DOS 5.0 can be told to reply with a lower
- version number to allow badly written older software to run
- properly.
-
- One final routine that should be of some value is the one that
- allows you to find out what kind of display is available. It
- tells you the specific adapter and whether the display is color
- or monochrome. There is one case in which it can be confused,
- however-- if the adapter is CGA, the display is assumed to be
- color, since there is no way for the computer to know any
- differently. So, although this routine provides a good idea of
- what is available, it would be a good idea to provide an option
- to tell the program that a monochrome display is attached.
- Microsoft normally uses "/B" for this purpose, so that might be
- a good standard to stick with.
-
- PROCEDURE GetDisplay (VAR Adapter: Integer; VAR Mono: Boolean);
-
- The adapter will be one of the following:
-
- 1 MDA 4 EGA
- 2 Hercules 5 MCGA
- 3 CGA 6 VGA
-
- Expression Evaluator page 10
-
- Unit: ExtMath
-
-
-
- The expression evaluator solves numeric equations. It allows you
- to find the result of an expression contained in a string.
- Normal algebraic precedence is used, e.g. 4+3*5 evaluates to 19.
- The usual numeric operators (*, /, +, -, ^) are supported
- (multiply, divide, add, subtract, and raise to a power).
- Negation is also supported. Parentheses can be used for
- overriding the default order of operations.
-
- You may use either double asterisk ("**") or caret ("^") symbols
- to indicate exponentiation.
-
- The constant PI is recognized, as are the following functions:
- ABS absolute value INT integer
- ACOS inverse cosine LOG natural log
- ASIN inverse sine SIN sine
- ATAN inverse tangent SQRT square root
- COS cosine TAN tangent
- FRAC fraction
-
- Trig functions expect angles in radians.
-
- To evaluate an expression, you pass it to the evaluator as a
- string. You will get back either an error code or a real result.
- See the CALC.PAS program for a working example.
-
- PROCEDURE Evaluate (Expression: String; VAR Result: Real;
- VAR ErrCode: Integer);
-
- An expression evaluator adds convenience to any program that
- needs to accept numbers. Why make someone reach for a calculator
- when number crunching is what a computer does best?
-
- Extensions to Pascal's Math page 11
-
- Unit: ExtMath
-
-
-
- For the most part, the math routines in this library are
- designed to provide alternatives to the math routines that come
- with Pascal. Still, Pascal's own math support is quite adequate
- for many purposes, so there's no sense in ignoring it. Here are
- some functions which improve on Pascal's math.
-
- { inverse cosine }
- FUNCTION ArcCos (Number: Real): Real;
- { 1.0 >= Number >= -1.0 }
-
- { inverse hyperbolic cosine }
- FUNCTION ArcCosH (Number: Real): Real;
-
- { inverse cotangent }
- FUNCTION ArcCot (Number: Real): Real;
-
- { inverse hyperbolic cotangent }
- FUNCTION ArcCotH (Number: Real): Real;
-
- { inverse cosecant }
- FUNCTION ArcCsc (Number: Real): Real;
-
- { inverse hyperbolic cosecant }
- FUNCTION ArcCscH (Number: Real): Real;
-
- { inverse secant }
- FUNCTION ArcSec (Number: Real): Real;
-
- { inverse hyperbolic secant }
- FUNCTION ArcSecH (Number: Real): Real;
-
- { inverse sine }
- FUNCTION ArcSin (Number: Real): Real;
- { 1.0 >= Number >= -1.0 }
-
- { inverse hyperbolic sine }
- FUNCTION ArcSinH (Number: Real): Real;
-
- { inverse hyperbolic tangent }
- FUNCTION ArcTanH (Number: Real): Real;
-
- { ceiling: smallest integer >= specified number }
- FUNCTION Ceil (Number: Real): Real;
-
- { hyperbolic cosine }
- FUNCTION CosH (Number: Real): Real;
-
- { cotangent }
- FUNCTION Cot (Number: Real): Real;
-
- Extensions to Pascal's Math page 12
-
- Unit: ExtMath
-
-
-
- { cosecant }
- FUNCTION Csc (Number: Real): Real;
-
- { convert degrees to radians }
- FUNCTION Deg2Rad (Number: Real): Real;
-
- { the constant "e" }
- FUNCTION e: Real;
-
- { error function }
- FUNCTION Erf (Number: Real): Real;
-
- { factorial }
- FUNCTION Fact (Number: Integer): Real;
-
- { floor: largest integer <= specified number }
- FUNCTION Floor (Number: Real): Real;
-
- { log (base 10) }
- FUNCTION Log (Number: Real): Real;
-
- { convert radians to degrees }
- FUNCTION Rad2Deg (Number: Real): Real;
-
- { raise a number to a power }
- FUNCTION Raise (Number: Real; Power: Integer): Real;
-
- { secant }
- FUNCTION Sec (Number: Real): Real;
-
- { hyperbolic secant }
- FUNCTION SecH (Number: Real): Real;
-
- { signum (integer) }
- FUNCTION SgnI (Number: Integer): Integer);
-
- { signum (real) }
- FUNCTION SgnR (Number: Real): Integer);
-
- { hyperbolic sine }
- FUNCTION SinH (Number: Real): Real;
-
- { tangent }
- FUNCTION Tan (Number: Real): Real;
-
- { hyperbolic tangent }
- FUNCTION TanH (Number: Real): Real;
-
- Joystick Support page 13
-
- Unit: Joystick
-
-
-
- There's little enough to say about the joystick. A PC may have
- up to two of them. Normally, a joystick has two buttons, and
- returns a pair of coordinates which describe the position in
- which it is being held. The coordinates vary depending on the
- individual joystick, the computer involved, and other factors,
- so it is wise to provide a calibration routine to customize your
- program for the joystick(s) involved.
-
- The FlightStick joystick has a dial for throttle control, which
- is available only in a one-joystick setup. The throttle value is
- returned as the Y coordinate of an imaginary second joystick.
-
- Coordinates (X, Y), where X is the horizontal and Y the vertical
- coordinate, range from around 0 to around 150 on my FlightStick.
- Since these values may vary significantly, however, they are
- returned as words.
-
- The state of the joystick buttons may be checked individually or
- all at once. If you need to know the state of multiple buttons,
- it is faster to do it all at once, but you may do it either way.
-
- FUNCTION ButtonA1: Boolean; { button 1 on 1st joystick }
- FUNCTION ButtonA2: Boolean; { button 2 on 1st joystick }
- FUNCTION ButtonB1: Boolean; { button 1 on 2nd joystick }
- FUNCTION ButtonB2: Boolean; { button 2 on 2nd joystick }
-
- PROCEDURE Buttons (VAR A1, A2, B1, B2: Boolean); { all buttons }
-
- The joystick positions are handled internally by a rather
- unfortunate method involving a timer, due to the way IBM
- designed the joystick interface. This makes getting the position
- rather slow. To alleviate the problem, all positions are
- returned at once.
-
- PROCEDURE Positions (VAR AX, AY, BX, BY: Word);
-
- Joystick support is handled through a set of BIOS routines which
- were added to the PC around 1985. These routines are not present
- in some of the oldest PCs.
-
- Keyboard Control page 14
-
- Unit: Keyboard
-
-
-
- The keyboard is not a particularly exciting or glamorous device.
- In fact, we tend to forget about it except when it gets in the
- way. Sometimes it's a hardware problem-- squishy or clacking
- keys, or perhaps a commonly-used key placed in an out-of-the-way
- location. Then again, sometimes it's the software that's the
- problem. There are many aspects of keyboard control, not all of
- which are necessarily related to input. This unit will let you
- handle the keyboard in ways you may not have realized were
- possible. Better yet, it can help make keyboard control easier
- than the users of your programs dreamed possible.
-
- Let's start out with keyboard output. Yep, not input-- output.
- We can stuff up to 15 keys into the keyboard buffer. Why would
- we ever want to do this? Perhaps to allow your program to pop-up
- a TSR automatically, to start another program after your program
- ends, or for creating key macros. You can enter extended key
- codes (like function keys) by using CHR$(0) before the scan
- code.
-
- PROCEDURE TypeIn (Keys: String);
-
- The usual keyboard action is quite sluggish. We can make it a
- lot crisper by changing the key repeat rate and the delay before
- repeating. This will work on ATs, but not PC/XT systems.
-
- PROCEDURE SpeedKey (RepDelay, RepRate: Integer);
-
- The delay may be 0-3 (1 by default):
-
- 0 250 milliseconds
- 1 500 milliseconds
- 2 750 milliseconds
- 3 1 second
-
- The repeat rate may be 0-31 (11 by default). The larger the
- number, the slower the speed-- 0 is around 30 cps, and 31 is
- around 2 cps.
-
- I generally prefer to have the keyboard cranked up to full
- speed, using RepDelay and RepRate both set to zero. This may be
- a bit too zippy for some people, and may cause keyboard buffer
- overflows with some games. Experiment with it to see what you
- like best.
-
- Of course, there may be reasons to make keyboard repeat less
- sensitive instead! That might be a good idea in programs written
- for small children, for example. You can adjust the keyboard
- equally well in either direction.
-
- Keyboard Control page 15
-
- Unit: Keyboard
-
-
-
- Pascal allows you to control one of the keys which can interrupt
- your program, namely the Break key. There's another dangerous
- key which PasWiz allows you to control-- the PrtSc (PrintScreen)
- key. PrtSc may not seem like a hazard at first glance, but if
- it's pressed by accident with no printer ready, or in a graphics
- mode which PrtSc doesn't understand how to print, the results
- can be pretty messy. So, we let you turn it off or on:
-
- PROCEDURE SetPrtSc (PrtScON: Boolean);
-
- Use FALSE to turn it off or TRUE to turn it back on. If you turn
- off PrtSc, you MUST remember to turn it back on again before
- your program ends! Otherwise, an interrupt vector will point
- into nowhere, causing probable chaos the next time PrtSc is
- pressed.
-
- Regardless of whether you've turned the PrtSc key off, you can
- print the screen yourself just as if PrtSc had been pressed:
-
- PROCEDURE PrintScreen;
-
- Now here's a strange one for you. When IBM brought out the
- 101-key keyboard, called the "enhanced" keyboard, they did
- something bizarre to the BIOS. They still allowed old keyboard
- calls to work, but they filtered out the new key codes so no one
- would see them. This made sure that no one would be able to use
- the capabilities of the "enhanced" keyboard without rewriting
- their programs. So, the keyboard has been around for years, and
- there are still few programs that even notice when you press
- F11. Pascal does not support the enhanced keyboard at all.
- Fortunately, PasWiz -does-. You can find out if an enhanced
- keyboard is installed with the EnhKbd function, which is in the
- Equipment unit.
-
- If there is an enhanced keyboard installed, you can activate it
- with this:
-
- PROCEDURE SetEnhKbd (Enhanced: Boolean);
-
- With enhanced keyboard support activated, all key requests that
- used the old services are translated to the new services. So,
- SetEnhKbd affects the ReadKey (in the CRT unit that comes with
- Pascal) and other Pascal functions as well as other PasWiz
- keyboard routines. Note that you MUST deactivate enhanced
- keyboard support before ending your program. Otherwise, an
- interrupt vector will point into nowhere, probably causing a
- crash on the next keypress!
-
- Keyboard Control page 16
-
- Unit: Keyboard
-
-
-
- If you're about to request important input, you may not want to
- chance having it answered from results of the keyboard buffer--
- could be that the user meant those keys for another purpose. In
- that case, it's a good approach to clear out the keyboard buffer
- just before the input:
-
- PROCEDURE ClearKbd;
-
- No keyboard unit would be complete without a selection of
- routines to check the shift states and get or set the keyboard
- toggles. Let's start with the toggles, which are so called
- because they get toggled from one state to another:
-
- FUNCTION CapsOn: Boolean; { Caps Lock }
-
- FUNCTION InsertOn: Boolean; { Insert }
-
- FUNCTION NumOn: Boolean; { Num Lock }
-
- FUNCTION ScrollOn: Boolean; { Scroll Lock }
-
- You can also turn the toggles off or on. It's courteous to
- restore the original toggle states once you end your program, so
- you might want to save the original values for that purpose.
- Then again, I guess that doesn't apply if your program is
- designed for the specific purpose of setting the toggles!
-
- PROCEDURE SetCaps (CapsLock: Boolean); { Caps Lock }
-
- PROCEDURE SetInsert (InsertKey: Boolean); { Insert }
-
- PROCEDURE SetNum (NumLock: Boolean); { Num Lock }
-
- PROCEDURE SetScroll (ScrollLock: Boolean); { Scroll Lock }
-
- Does anyone actually use ScrollLock for anything? Just
- curious...
-
- Keyboard Control page 17
-
- Unit: Keyboard
-
-
-
- The shift keys are unique in many respects. They don't return
- codes that can be detected with ReadKey or stuffed into the
- keyboard buffer; several can be pressed at the same time; and
- they don't repeat. You can detect 'em with PasWiz, at any rate:
-
- FUNCTION AltPress: Boolean; { any ALT }
-
- FUNCTION CtrlPress: Boolean; { any CTRL }
-
- FUNCTION ShiftPress: Boolean; { any SHIFT }
-
- FUNCTION LAltPress: Boolean; { left ALT }
-
- FUNCTION LCtrlPress: Boolean; { left CTRL }
-
- FUNCTION LShiftPress: Boolean; { left SHIFT }
-
- FUNCTION RAltPress: Boolean; { right ALT }
-
- FUNCTION RCtrlPress: Boolean; { right CTRL }
-
- FUNCTION RShiftPress: Boolean; { right SHIFT }
-
- NOTE that LAltPress, LCtrlPress, RAltPress, and RCtrlPress are
- ONLY available for enhanced keyboards. They will not return
- useful results on older keyboards.
-
- String Stuff page 18
-
- Unit: Strings
-
-
-
- Strings have always been something of an afterthought in Pascal.
- This unit brings in the heavy artillery! The PasWiz string
- routines may be divided into the following categories:
- comparison, compression, encryption, extraction, searching, and
- miscellaneous (mostly alteration). Let's take up these
- categories one at a time.
-
- The compression routines are designed to work with ordinary text
- strings. The strings may not contain IBM extended-ASCII codes
- (CHR($80)-CHR($FF)), as these are used in the compression.
- Compression works on spaces, which will give you an average of
- 15% compression on normal text. If you compress printable text
- (i.e., no control codes), you'll get printable text in return,
- which makes these routines handy for use with text files.
- Compression and decompression is done at an extreme rate of
- speed and will not affect the timing of your program in any
- noticeable fashion.
-
- FUNCTION Bsq (St: String): String; { compress a string }
-
- FUNCTION BUsq (St: String): String; { uncompress a string }
-
- Comparing two strings is easy enough in Pascal, but not as
- flexible as might be desired for some applications. You can tell
- if two strings match exactly, but not if they're reasonably
- close matches. PasWiz has two fuzzy comparison routines which
- can help.
-
- The Soundex routine uses a long-established algorithm to
- convert a word into a code which represents the sound of the
- word. It is fast and can work well under properly defined
- circumstances; for instance, it will tell you that "Smith"
- sounds just like "Smythe", but not like "Banks". Between the
- need for speed and the vagaries of the English language,
- however, you may find matches which don't work as well. Soundex
- is certain that "Knight" sounds just like "Smashed", for
- example. So, it may be perfect for something like a phone book,
- but not for a spelling checker!
-
- FUNCTION Soundex (St: String): String;
-
- The Bickel routine, on the other hand, tells you how closely two
- words match. This is a relative measure, not an absolute
- measure, so you'd probably want to search through an entire
- dictionary and just keep the words which matched best. The
- Bickel algorithm is slower than Soundex but is much more
- precise.
-
- FUNCTION Bickel (St1, St2: String): Integer;
-
- String Stuff page 19
-
- Unit: Strings
-
-
-
- There are many cases in which you might want to keep data
- private. The PasWiz encryption routines provide a simple and
- extremely fast method for password-protecting text. The
- encryption technique is trivial and will not withstand any
- concerted attack, but should suffice for casual use. It will
- help if you pick a longish password of unusual characters, for
- example '[^.mE@@&o}' (don't use this example itself, please)!
-
- There are two encryption routines (which also work as decryption
- routines). The first is designed to produce printable, if
- bizarre-looking, results which are suited for use with text
- files. Text to be encrypted by this routine may not include IBM
- extended-ASCII characters (CHR($80) - CHR($FF)), since these are
- used to insure printable text.
-
- FUNCTION CipherP (St, Passwd: String): String;
-
- The other routine will work with any sort of text, but is not
- guaranteed to produce printable results. So, it's not suited for
- use with text files.
-
- FUNCTION Cipher (St, Passwd: String): String;
-
- Of the extraction routines, two are merely convenient
- rephrasings of the Copy function which allow you to grab a
- substring from the left or right side of a string:
-
- FUNCTION Left (St: String; Len: Integer): String;
-
- FUNCTION Right (St: String; Len: Integer): String;
-
- Another extraction routine is more interesting. It allows you to
- extract a substring from a string which contains delimited
- information. For instance, consider the following name and
- address string. It has three fields, each separated by an
- asterisk. We can use Extract to grab any individual field:
-
- St := 'Tom Hanlin*3544 E. Southern Ave. #104*Mesa, AZ 85204';
- FOR PrtAddress := 1 TO 3 DO BEGIN
- AddressLine := Extract(St, '*', PrtAddress);
- WriteLn(AddressLine);
- END;
-
- The extract function is defined as follows:
-
- FUNCTION Extract (St, Delimiter: String;
- Index: Integer): String;
-
- If you try to extract a field which doesn't exist, a null string
- will be returned. Field delimiters may be anything at all, by
- the way-- one possible use for Extract might be to block-read a
- text file, splitting it apart in memory by using the carriage
- return and linefeed as a delimiter.
-
- String Stuff page 20
-
- Unit: Strings
-
-
-
- PasWiz provides an assortment of string search routines. One is
- a simple modification of Pos which allows you to start the
- search at a given place in the string:
-
- FUNCTION Instr (Start: Integer; SubSt, St: String): Integer;
-
- Another works like Pos, but returns the last match rather than
- the first match:
-
- FUNCTION RPos (SubSt, St: String): Integer;
-
- Of course, you don't always want to search for something in
- specific. You might be more interested in finding the first
- character that fits into a given category or categories, like
- perhaps numbers or letters. No problem:
-
- FUNCTION TypePos (ChType: Integer; St: String): Integer;
-
- The ChType value is formed by adding the numbers which represent
- the desired categories. This can also be used to search for the
- first character which is not of a given type, since the
- categories are exclusive:
-
- 1 alphabetic
- 2 numeric
- 4 symbols
- 8 control codes (ASCII 0-31, 127)
- 16 graphics codes (ASCII 128-255)
- 32 space (ASCII 32)
-
- That covers the string routines which can be readily
- categorized. Most of the remaining routines are designed to
- alter a string in one way or another. This includes being able
- to remove selected characters, substrings, types of characters,
- or repeated characters from a string; trimming the left or right
- side of a string of blanks; converting to uppercase, lowercase,
- or using the correct capitalization for a proper name; replacing
- one substring with another; reversing a string; and forming a
- new string by repeating a given substring.
-
- The "case", "trim", and "reverse" functions are pretty much
- self-explanatory:
-
- FUNCTION LowerCase (St: String): String; { lowercase }
-
- FUNCTION NameCase (St: String): String; { name case }
-
- FUNCTION UpperCase (St: String): String; { upper case }
-
- FUNCTION LTrim (St: String): String; { left trim }
-
- FUNCTION RTrim (St: String): String; { right trim }
-
- FUNCTION Reverse (St: String): String; { reverse }
-
- String Stuff page 21
-
- Unit: Strings
-
-
-
- The Crunch function removes adjacent repetitions of a substring.
- This is particularly handy for parsing user input, for example--
- you can use it to remove repeated spaces between options, etc.
-
- FUNCTION Crunch (SubSt, St: String): String;
-
- The Dupe function forms a string by repeating a substring. It's
- handy when you need a string of a given number of spaces,
- zeroes, or nulls. It can also be used for drawing horizontal
- lines and other applications.
-
- FUNCTION Dupe (Count: Integer; SubSt: String): String;
-
- There are many times when it's nice to be able to replace all
- occurrences of one substring with another. PasWiz can do that,
- no problem. You don't have to worry about recursion, either--
- each occurrence is replaced only once, even if the replacement
- substring contains the target substring.
-
- FUNCTION Replace (OldSubSt, NewSubSt, St: String): String;
-
- Of course, you can delete a substring by replacing it with a
- null string. It's faster to use the routine designed for that
- purpose, though:
-
- FUNCTION StripSt (SubSt, St: String): String;
-
- You may also delete specified characters from a string:
-
- FUNCTION StripCh (ChList, St: String): String;
-
- Next, a routine which deletes specified types of characters from
- a string. This can be very good for screening user input.
-
- FUNCTION StripType (ChType: Integer; St: String): String;
-
- The ChType value is formed by adding the numbers which represent
- the desired categories:
-
- 1 alphabetic
- 2 numeric
- 4 symbols
- 8 control codes (ASCII 0-31, 127)
- 16 graphics codes (ASCII 128-255)
- 32 space (ASCII 32)
-
- PasWiz also has a specialized variant on the Val function which
- converts a number from a string to a WORD (or INTEGER) value. No
- error checking is provided. This is very small and fast:
-
- FUNCTION WVal (St: STRING): WORD;
-
- Music page 22
-
- Unit: Music
-
-
-
- Granted, the PC has never been known for its wonderful sound
- capabilities. Still, it has more potential than you might guess,
- especially given the utterly minimal Sound/Delay/NoSound
- routines that are provided with Pascal. The Music unit makes it
- much easier to use sounds by providing an actual music language.
- The BACHINV and ENTERTNR demo programs demonstrate some of the
- possibilities.
-
- The PasWiz music language is nearly identical to that offered by
- the BASIC PLAY statement. The major difference is that the "MB"
- command (play the music as a background task) is not supported.
- I'll add that later, if I get enough requests.
-
- There are only two music procedures:
-
- PROCEDURE ResetMF;
-
- PROCEDURE PlayMF(Sounds: String);
-
- The ResetMF procedure is used to reset all music parameters to
- the default values. It would typically be used after finishing a
- song to restore the music handler for the next song.
-
- The PlayMF procedure is the one that does the real work. Here's
- a list of the music commands supported:
-
- MB play music as a background task (ignored)
- MF play music as a foreground task (ignored)
- ML legato (8/8 note length)
- MN normal music (7/8 note length)
- MN staccato (6/8 note length)
- Ln Length of notes (n = 1-64; note length = 1/n)
- Nn Note number (n = 0-84; 0 is a rest)
- On Octave (n = 0-6, default 4)
- Pn Pause (n = 1-64; pause length = 1/n)
- Tn Tempo (n = 32-255, default 120; quarter notes/minute)
- < move up an octave (max 6)
- > move down an octave (min 0)
-
- You can also use the actual letters of the notes (C, D, E, F, G,
- A, and B). If you're not particularly musical, these correspond
- to "do, re, mi, fa, so, la, ti" (with the final "do" being C
- again, but an octave higher). To play a scale, you'd use
- 'CDEFGAB>C'. The notes may be followed by dots, by note lengths,
- and by sharp or flat symbols (a '+' or '#' for a sharp, a '-'
- for a flat). For example, 'D-.' is a dotted D flat. The dot
- means that the note will play for half again its usual length.
- Dots can be repeated.
-
- I might note (ahem) that the so-called "ANSI" music offered by
- some BBSes and comm programs is based on this same music
- language. If you're writing telecomm software, this unit makes
- it trivial to add sound.
-
- Mouse page 23
-
- Unit: Mouse
-
-
-
- Considering the ubiquity of the mouse these days, it's a marvel
- to me that none of the popular programming languages provides
- any support for it. Well, BASIC supports it via light pen
- emulation, but that scarcely counts. Anyway, this is a simple
- little unit which provides you direct access to the mouse
- driver. It will work with any Microsoft-compatible mouse driver.
-
- A few words are necessary on mouse handling. To begin with, the
- best time to check for a mouse is immediately after you've
- established the desired video mode. The mouse driver initializes
- certain information when you check for it, so it's a good idea
- to check for it only once, at the appropriate time.
-
- The mouse cursor was implemented in a rather bizarre manner. If
- you call ShowCursor, you're guaranteed that the mouse cursor
- will be visible; however, this also increments an internal
- visibility flag. If you call ShowCursor multiple times, you will
- also have to call HideCursor multiple times before the dang
- cursor actually disappears.
-
- The mouse driver was apparently implemented without any thought
- for the future. In text mode, it returns coordinates based on
- CGA hi-res graphics mode-- 640x200 instead of the expected
- 80x25. If you use the mouse driver in text mode, you'll have to
- compensate for this (divide coordinates by 8 to convert to text
- mode, or multiply by 8 to convert to the mouse virtual mode).
- The CGA low-res 320x200 graphics mode is implemented likewise.
- It seems Microsoft thought that 640x200 would be the ultimate
- resolution, so they translated everything to a 640x200 virtual
- mode. Arrgh. Fortunately, this does not apply to video modes
- other than text and CGA graphics.
-
- I understand that it's possible to get the mouse working in
- Hercules graphics mode, but I'm not sure what the details are.
- If anyone out there knows, please let me know, and I'll pass it
- along.
-
- Since Microsoft was initially very tight-lipped about the mouse
- functions, older mouse drivers for Microsoft-compatible rodents
- don't necessarily have all the functions available (this
- includes Logitech, amazingly enough). The Microsoft mouse driver
- continues to be updated in a rapid and haphazard manner, so
- keeping up-to-date is no guarantee. However, if you have any
- problems with these routines, you can almost certainly clear
- them up by getting a newer mouse driver. The routines in this
- unit are almost all old, well-established functions. "Iffy" ones
- are marked for your convenience.
-
- Mouse page 24
-
- Unit: Mouse
-
-
-
- The first function to consider simply tells you whether a mouse
- is available, and if so, how many buttons it has. It also resets
- the mouse driver, so it should be used only at the beginning of
- your program (or after changing the video mode).
-
- FUNCTION Init: Integer;
- { returns 0 if no mouse, else # of buttons }
-
- Most often, you'll want to know which mouse button(s) are
- pressed and where the mouse cursor is:
-
- FUNCTION LeftButton: Boolean;
- { TRUE if pressed }
-
- FUNCTION MidButton: Boolean;
- { always FALSE on 2-button rodents }
-
- FUNCTION RightButton: Boolean;
- { TRUE if pressed }
-
- FUNCTION WhereX: Integer;
- { X-coord (see notes on previous page) }
-
- FUNCTION WhereY: Integer;
- { Y-coord (see notes on previous page) }
-
- As well as finding the current mouse information, it's possible
- to find out what the mouse has been doing since you last
- checked. Two sets of routines exist: one to find out how many
- times a button was pressed and where it was at the last press,
- and one to find out how many times a button was released and
- where it was at the last release.
-
- PROCEDURE LeftClick(VAR Count, X, Y: Integer);
-
- PROCEDURE MidClick(VAR Count, X, Y: Integer);
-
- PROCEDURE RightClick(VAR Count, X, Y: Integer);
-
- PROCEDURE LeftRelease(VAR Count, X, Y: Integer);
-
- PROCEDURE MidRelease(VAR Count, X, Y: Integer);
-
- PROCEDURE RightRelease(VAR Count, X, Y: Integer);
-
- Mouse page 25
-
- Unit: Mouse
-
-
-
- There's one more informational routine. It tells you the basic
- mouse software and hardware stats: driver version, connector
- type (serial, bus, etc), and IRQ used. This routine is slightly
- hazardous in that, although Microsoft claims it has existed from
- the first, other manufacturers (including Logitech) have taken
- some time to implement it. In other words, it may not return
- useful information. The routine conducts a self-check and will
- return all zeroes if it suspects the information is not good,
- but even so... proceed with care.
-
- PROCEDURE Info(VAR Version: Real; VAR Connector, IRQ: Byte);
-
- Connector info: 1=bus, 2=serial, 3=InPort, 4=PS/2,
- 5=Hewlett-Packard IRQs: 0=PS/2; 2-5, 7 are actual IRQ numbers.
- It is conceivable that higher IRQ numbers may be supported on
- AT-type machines, though not by Microsoft.
-
- Of course, you can set mouse info as well as retrieving it. The
- following routines are pretty well self-explanatory (don't
- forget the notes about the strange text-mode and CGA coordinate
- handling, and cursor handling):
-
- { hide the mouse cursor }
- PROCEDURE HideCursor;
-
- { (maybe) make the cursor visible }
- PROCEDURE ShowCursor;
-
- { set the cursor position }
- PROCEDURE GotoXY(X, Y: Integer);
-
- { set the cursor range }
- PROCEDURE Window(X1, Y1, X2, Y2: Integer);
-
- There are other possibilities supported by the mouse driver that
- I have not implemented here. They're mostly on the rather
- esoteric side and are not supported by anything except recent
- Microsoft mouse drivers and perhaps some close compatibles, such
- as Logitech.
-
- Among the mouse capabilities I haven't implemented are finding
- out how fast and in what direction the mouse is moving, the
- coordinate size of the screen as far as the mouse is concerned,
- finding out the video modes that the mouse driver understands,
- setting mouse speed and sensitivity parameters, setting up an
- interrupt-driven system for handling mouse events, and a few
- others.
-
- Mouse page 26
-
- Unit: Mouse
-
-
-
- None of these missing capabilities is particularly vital (or
- even useful) for the average mouse application. However, if
- you're interested in any of these capabilities, let me know
- which ones, and I'll be glad to add them to PasWiz.
-
- Note: if you're confused at how I can get away with duplicating
- the names of existing procedures... well, it's easy enough.
- Let's consider WhereX. It means one thing to Pascal's Crt unit
- and another to the PasWiz Mouse unit. Since the Mouse unit
- doesn't use the Crt unit, it has no problem with any ambiguity.
- Existing programs that don't use the Mouse unit will likewise
- have no problems, since they don't know about the new routine.
- Suppose you want to use both the Crt and Mouse units together,
- however? There's the rub!
-
- You can specify a routine from a given unit by including the
- unit name when you use the routine. For instance:
-
- X := Mouse.WhereX; { get the mouse cursor position }
-
- X := Crt.WhereX; { get the normal cursor position }
-
- This allows multiple units to use the same names for things.
- While this may seem like a bit of a pain, since you have to
- specify which you want, it has a major built-in advantage if
- used properly. What's properly? When a routine in one unit works
- just like a routine by the same name in another unit. When I
- call the mouse routine "WhereX", for instance, I've also told
- you what it is for and how to use it. So, the name itself
- contains a lot of useful information on how to use the routine!
- That's what I call a major advantage.
-